#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h> 
#include <time.h>

int buffer[1000], origbuff[1000];		//aloca um buffer de 1000 posicoes


void error(const char *msg)
{
    perror(msg);
    exit(0);
}

double t1,t2;
double tempo()
{
 struct timeval tv;
 gettimeofday(&tv,0);
 return tv.tv_sec + tv.tv_usec/1e6;
}

void atraso(){
	double at1, at2;
	at1 = tempo();
	while((at2-at1)<1){
		at2 = tempo();
	}
}

    
void server()		//funcao principal
{
     
     //***************** variáveis ************************
	 
     int sockfd, newsockfd, newsockfd2, portno;		//file descriptors e o numero da porta
     socklen_t clilen;					//clilen guarda o tamanho do endereço do cliente
     
     struct sockaddr_in					//estrutura contendo um endereço de internet
			serv_addr, cli_addr;
     int n;								//contem o numero de caracteres lidos ou escritos
	 int i,k,aux;						//auxiliares
	 //*************** criaçao do socket **************
     sockfd = socket(AF_INET, SOCK_STREAM, 0); 		//sockfd recebera o descriptor do sock criado.
     if (sockfd < 0) 
        error("ERRO ao criar o socket");
     
     bzero( (char *) &serv_addr, sizeof(serv_addr) );	//funcao que zera o buffer serv_addr
     
     //******************************
			portno = 10100;								//numero da porta que o socket usará
     //******************************
     
     serv_addr.sin_family = AF_INET;
     serv_addr.sin_addr.s_addr = INADDR_ANY;
     serv_addr.sin_port = htons(portno);
     
     //*********** bind do socket na porta *****
     if (bind(sockfd, (struct sockaddr *) &serv_addr, sizeof(serv_addr)) < 0) 
              error("ERRO no bind");
     
     //******** listen ********
     listen(sockfd,5);
     clilen = sizeof(cli_addr);
     
     //***************** accept o socket dos clientes *********
     newsockfd = accept(sockfd, (struct sockaddr *) &cli_addr, &clilen);
     if (newsockfd < 0) 
          error("ERRO ao aceitar outra conexao");
     newsockfd2 = accept(sockfd, (struct sockaddr *) &cli_addr, &clilen);
     if (newsockfd2 < 0) 
          error("ERRO ao aceitar outra conexao");
     
     
     //**********************************************
     //********* lendo do cliente para o buffer *****
     //*********************************************
     t1 = tempo();
     
     bzero(buffer,sizeof(buffer)/4);						//zera o buffer
     bzero(origbuff,sizeof(origbuff)/4);					//zera o buffer original
     
     n = read(newsockfd,origbuff,sizeof(origbuff));		//executa o read dos 125 valores iniciais
     if (n < 0) error("ERRO ao ler do socket");
     
     n = read(newsockfd2,&origbuff[sizeof(origbuff)/8],sizeof(origbuff)/2);		//executa o read dos 125 ultimos valores
     if (n < 0) error("ERRO ao ler do socket");
     
     
     for(i=0;i<sizeof(buffer)/4;i++){
		buffer[i] = origbuff[i];
	 }
     
	//****** copia do buffer original **
     
     for(i=0;i<sizeof(buffer)/4;i++){
		buffer[i] = origbuff[i];
	 }
     
     
     //***** ordenaçao do vetor recebido **********
     
	 for(i=0;i<sizeof(buffer)/4;i++){	//para todos os valores
			for(k=0;k<sizeof(buffer)/4;k++){		//percorrer todo o vetor
				if(buffer[i]<buffer[k]){	//se o valor i for menor que o valor k
					aux = buffer[i];		//troca os dois valores
					buffer[i] = buffer[k];
					buffer[k] = aux;
				}
			}
	 }
	 t2 = tempo();
     
     
     
	 
     
     
     close(newsockfd);
     close(newsockfd2);
     close(sockfd);
}






int client(char *argv, int port){
	int sockfd, portno, n;
    struct sockaddr_in serv_addr;
    struct hostent *server;

    //******************************
			portno = port;						//numero da porta que o socket usará
    //******************************
    
    //********* criação do sock **********
    sockfd = socket(AF_INET, SOCK_STREAM, 0);	
    if (sockfd < 0) 
        error("ERRO ao abrir socket");
    
    //********* definicao do server ***********
    server = gethostbyname(argv);
    if (server == NULL) {
        fprintf(stderr,"ERRO, nao existe tal host\n");
        exit(0);
    }
    
    bzero((char *) &serv_addr, sizeof(serv_addr));		//zera o buffer serv_addr
    serv_addr.sin_family = AF_INET;
    serv_addr.sin_port = htons(portno);
    serv_addr.sin_addr = *((struct in_addr *)server->h_addr);
    
    
    
    //*********** conexao com o server ************
    if (connect(sockfd,(struct sockaddr *) &serv_addr,sizeof(serv_addr)) < 0) 
        error("ERRO ao conectar");
    
    
    //**************************************
    //******* escrevendo para o server *********
    //**************************************
    
    
    
    n = write(sockfd,buffer,(sizeof(buffer)));		//escrever valores para o server
    if (n < 0) 
         error("ERRO ao escrever para o socket");
    printf("%d numeros enviados\n",n/4);
    
    
    close(sockfd);
    return 0;
}


int main(int argc, char *argv[]){
    int i;
    char *host1 = "localhost";
    char *host2 = "localhost";
    char *host3 = "localhost";
    char *host4 = "localhost";
    char *host5 = "localhost";
    char *host6 = "localhost";
    char *host7 = "localhost";
    char *host8 = "localhost";
    server();
    
    printf("\n\nVetor recebido: [");
	 for(i=0;i<sizeof(origbuff)/8;i++){
		 printf(" %d",origbuff[i]);
	 }
	 printf(" ]\t+\t[");
	 for(i=sizeof(origbuff)/8;i<sizeof(origbuff)/4;i++){
		 printf(" %d",origbuff[i]);
	 }
	printf(" ]\n\n");
	
	printf("\n\nVetor ordenado: [");
     for(i=0;i<sizeof(buffer)/4;i++){		//para todos os valores
		 printf(" %d",buffer[i]);			//imprimir o buffer
	 }
	 printf(" ]\n");
	 
	 printf("\nTempo no X-MEN: %.6lf segundos.\n\n",t2-t1);
    
	//atraso();
    client(host1,10107);
	//atraso();
    client(host2,10108);
	//atraso();
    client(host3,10109);
	//atraso();
    client(host4,10110);
	//atraso();
    client(host5,10111);
	//atraso();
    client(host6,10112);
	//atraso();
    client(host7,10113);
    //atraso();
    client(host8,10114);
    
    return 0;
}
